﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="HpcDataContractsTranslator.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace HpcSchedulerManagement.DataContracts
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Microsoft.Hpc.Scheduler.Properties;

    public static class HpcDataContractsTranslator
    {
        public static ArrayOfProperty TaskToArrayOfPropeties(SchedulerTask task)
        {
            var array = new ArrayOfProperty();
            AddProperty(array, TaskPropertyIds.Name, task.Name);
            AddProperty(array, TaskPropertyIds.MinCores, task.MinCores);
            AddProperty(array, TaskPropertyIds.MaxCores, task.MaxCores);
            AddProperty(array, TaskPropertyIds.MinNodes, task.MinNodes);
            AddProperty(array, TaskPropertyIds.MaxNodes, task.MaxNodes);
            AddProperty(array, TaskPropertyIds.MinSockets, task.MinSockets);
            AddProperty(array, TaskPropertyIds.MaxSockets, task.MaxSockets);
            AddProperty(array, TaskPropertyIds.RequiredNodes, task.RequiredNodes);
            AddProperty(array, TaskPropertyIds.CommandLine, task.CommandLine);
            AddProperty(array, TaskPropertyIds.WorkDirectory, task.WorkDirectory);
            AddProperty(array, TaskPropertyIds.DependsOn, task.DependsOn);
            AddProperty(array, TaskPropertyIds.IsExclusive, task.IsExclusive);
            AddProperty(array, TaskPropertyIds.IsRerunnable, task.IsRerunnable);
            AddProperty(array, TaskPropertyIds.StdOutFilePath, task.StdOutFilePath);
            AddProperty(array, TaskPropertyIds.StdInFilePath, task.StdInFilePath);
            AddProperty(array, TaskPropertyIds.StdErrFilePath, task.StdErrFilePath);
            AddProperty(array, TaskPropertyIds.RuntimeSeconds, task.RuntimeSeconds);
            AddProperty(array, TaskPropertyIds.StartValue, task.StartValue);
            AddProperty(array, TaskPropertyIds.EndValue, task.EndValue);
            AddProperty(array, TaskPropertyIds.IncrementValue, task.IncrementValue);
            AddProperty(array, TaskPropertyIds.UserBlob, task.UserBlob);

            return array;
        }

        public static ArrayOfProperty JobToArrayOfProperties(SchedulerJob job)
        {
            var array = new ArrayOfProperty();
            AddProperty(array, JobPropertyIds.Name, job.Name);
            AddProperty(array, JobPropertyIds.UserName, job.UserName);
            AddProperty(array, JobPropertyIds.EncryptedPassword, job.Password);
            AddProperty(array, JobPropertyIds.Project, job.Project);
            AddProperty(array, JobPropertyIds.UnitType, job.UnitType);
            AddProperty(array, JobPropertyIds.MinCores, job.MinCores);
            AddProperty(array, JobPropertyIds.MaxCores, job.MaxCores);
            AddProperty(array, JobPropertyIds.MinNodes, job.MinNodes);
            AddProperty(array, JobPropertyIds.MaxNodes, job.MaxNodes);
            AddProperty(array, JobPropertyIds.MinSockets, job.MinSockets);
            AddProperty(array, JobPropertyIds.MaxSockets, job.MaxSockets);
            AddProperty(array, JobPropertyIds.RunUntilCanceled, job.RunUntilCanceled);
            AddProperty(array, JobPropertyIds.IsExclusive, job.IsExclusive);
            AddProperty(array, JobPropertyIds.RequestedNodes, job.RequestedNodes);
            AddProperty(array, JobPropertyIds.NodeGroups, job.NodeGroups);
            AddProperty(array, JobPropertyIds.OrderBy, job.OrderBy);
            AddProperty(array, JobPropertyIds.JobTemplate, job.JobTemplate);
            AddProperty(array, JobPropertyIds.SoftwareLicense, job.SoftwareLicense);
            AddProperty(array, JobPropertyIds.Owner, job.Owner);
            AddProperty(array, JobPropertyIds.Progress, job.Progress);
            AddProperty(array, JobPropertyIds.ProgressMessage, job.ProgressMessage);
            AddProperty(array, JobPropertyIds.TargetResourceCount, job.TargetResourceCount);
            AddProperty(array, JobPropertyIds.Priority, job.Priority);
            AddProperty(array, JobPropertyIds.RuntimeSeconds, job.RuntimeSeconds);
            AddProperty(array, JobPropertyIds.RequeueCount, job.RequeueCount);
            AddProperty(array, JobPropertyIds.AutoRequeueCount, job.AutoRequeueCount);
            AddProperty(array, JobPropertyIds.AutoCalculateMax, job.AutoCalculateMax);
            AddProperty(array, JobPropertyIds.AutoCalculateMin, job.AutoCalculateMin);
            AddProperty(array, JobPropertyIds.FailOnTaskFailure, job.FailOnTaskFailure);
            AddProperty(array, JobPropertyIds.MaxCoresPerNode, job.MaxCoresPerNode);
            AddProperty(array, JobPropertyIds.MinMemory, job.MinMemory);
            AddProperty(array, JobPropertyIds.MaxMemory, job.MaxMemory);
            AddProperty(array, JobPropertyIds.NotifyOnStart, job.NotifyOnStart);
            AddProperty(array, JobPropertyIds.NotifyOnCompletion, job.NotifyOnCompletion);
            AddProperty(array, JobPropertyIds.ClientSource, job.ClientSource);
            AddProperty(array, JobPropertyIds.ExpandedPriority, job.ExpandedPriority);
            AddProperty(array, JobPropertyIds.ServiceName, job.ServiceName);
            AddProperty(array, JobPropertyIds.EmailAddress, job.EmailAddress);
            AddProperty(array, JobPropertyIds.Password, job.Password);

            return array;
        }

        public static SchedulerJob JobFromArrayOfProperties(IEnumerable<Property> properties)
        {
            var job = new SchedulerJob();

            if (properties == null)
            {
                return job;
            }

            job.Id = GetIntProperty(JobPropertyIds.Id, properties);
            job.Name = GetStringProperty(JobPropertyIds.Name, properties);
            job.Owner = GetStringProperty(JobPropertyIds.Owner, properties);
            job.UserName = GetStringProperty(JobPropertyIds.UserName, properties);
            job.Project = GetStringProperty(JobPropertyIds.Project, properties);
            job.RuntimeSeconds = GetIntProperty(JobPropertyIds.RuntimeSeconds, properties);
            job.SubmitTime = GetStringProperty(JobPropertyIds.SubmitTime, properties);
            job.CreateTime = GetStringProperty(JobPropertyIds.CreateTime, properties);
            job.EndTime = GetStringProperty(JobPropertyIds.EndTime, properties);
            job.StartTime = GetStringProperty(JobPropertyIds.StartTime, properties);
            job.State = (JobState)GetEnumProperty(JobPropertyIds.State, properties, typeof(JobState), JobState.Configuring);
            job.MinCores = GetIntProperty(JobPropertyIds.MinCores, properties);
            job.MaxCores = GetIntProperty(JobPropertyIds.MaxCores, properties);
            job.MinNodes = GetIntProperty(JobPropertyIds.MinNodes, properties);
            job.MaxNodes = GetIntProperty(JobPropertyIds.MaxNodes, properties);
            job.MinSockets = GetIntProperty(JobPropertyIds.MinSockets, properties);
            job.MaxSockets = GetIntProperty(JobPropertyIds.MaxSockets, properties);
            job.UnitType = (UnitType)GetEnumProperty(JobPropertyIds.UnitType, properties, typeof(UnitType), UnitType.Core);
            job.RequestedNodes = GetStringProperty(JobPropertyIds.RequestedNodes, properties);
            job.IsExclusive = GetBoolProperty(JobPropertyIds.IsExclusive, properties);
            job.RunUntilCanceled = GetBoolProperty(JobPropertyIds.RunUntilCanceled, properties);
            job.FailOnTaskFailure = GetBoolProperty(JobPropertyIds.FailOnTaskFailure, properties);
            job.AutoCalculateMax = GetBoolProperty(JobPropertyIds.AutoCalculateMax, properties);
            job.AutoCalculateMin = GetBoolProperty(JobPropertyIds.AutoCalculateMin, properties);
            job.RequeueCount = GetIntProperty(JobPropertyIds.RequeueCount, properties);
            job.MinMemory = GetIntProperty(JobPropertyIds.MinMemory, properties);
            job.MaxMemory = GetIntProperty(JobPropertyIds.MaxMemory, properties);
            job.MinCoresPerNode = GetIntProperty(JobPropertyIds.MinCoresPerNode, properties);
            job.MaxCoresPerNode = GetIntProperty(JobPropertyIds.MaxCoresPerNode, properties);
            job.SoftwareLicense = GetStringProperty(JobPropertyIds.SoftwareLicense, properties);
            job.OrderBy = GetStringProperty(JobPropertyIds.OrderBy, properties);
            job.Progress = GetIntProperty(JobPropertyIds.Progress, properties);
            job.ProgressMessage = GetStringProperty(JobPropertyIds.ProgressMessage, properties);
            job.TargetResourceCount = GetIntProperty(JobPropertyIds.TargetResourceCount, properties);
            job.JobTemplate = GetStringProperty(JobPropertyIds.JobTemplate, properties);
            job.Priority = (JobPriority)GetEnumProperty(JobPropertyIds.Priority, properties, typeof(JobPriority), JobPriority.Normal);
            job.NotifyOnStart = GetBoolProperty(JobPropertyIds.NotifyOnStart, properties);
            job.NotifyOnCompletion = GetBoolProperty(JobPropertyIds.NotifyOnCompletion, properties);
            job.EmailAddress = GetStringProperty(JobPropertyIds.EmailAddress, properties);
            job.ServiceName = GetStringProperty(JobPropertyIds.ServiceName, properties);
            job.ExpandedPriority = GetIntProperty(JobPropertyIds.ExpandedPriority, properties);
            job.ClientSource = GetStringProperty(JobPropertyIds.ClientSource, properties);
            job.Preemptable = GetBoolProperty(JobPropertyIds.Preemptable, properties);
            job.HoldUntil = GetStringProperty(JobPropertyIds.HoldUntil, properties);
            job.HasRuntime = GetBoolProperty(JobPropertyIds.HasRuntime, properties);
            job.CanGrow = GetBoolProperty(JobPropertyIds.CanGrow, properties);
            job.CanShrink = GetBoolProperty(JobPropertyIds.CanShrink, properties);
            job.PreviousState = (JobState)GetEnumProperty(JobPropertyIds.PreviousState, properties, typeof(JobState), JobState.Configuring);
            job.ChangeTime = GetStringProperty(JobPropertyIds.ChangeTime, properties);

            return job;
        }

        public static SchedulerTask TaskFromArrayOfProperties(IEnumerable<Property> properties)
        {
            var task = new SchedulerTask();

            if (properties == null)
            {
                return task;
            }

            task.Id = GetIntProperty(TaskPropertyIds.Id, properties);
            task.Name = GetStringProperty(TaskPropertyIds.Name, properties);
            task.State = (TaskState)GetEnumProperty(TaskPropertyIds.State, properties, typeof(TaskState), TaskState.Configuring);
            task.PreviousState = (TaskState)GetEnumProperty(TaskPropertyIds.PreviousState, properties, typeof(TaskState), TaskState.Configuring);
            task.ParentJobId = GetIntProperty(TaskPropertyIds.ParentJobId, properties);
            task.RuntimeSeconds = GetIntProperty(TaskPropertyIds.RuntimeSeconds, properties);
            task.UnitType = (UnitType)GetEnumProperty(TaskPropertyIds.UnitType, properties, typeof(UnitType), UnitType.Core);
            task.MinCores = GetIntProperty(TaskPropertyIds.MinCores, properties);
            task.MaxCores = GetIntProperty(TaskPropertyIds.MaxCores, properties);
            task.MinNodes = GetIntProperty(TaskPropertyIds.MinNodes, properties);
            task.MaxNodes = GetIntProperty(TaskPropertyIds.MaxNodes, properties);
            task.MinSockets = GetIntProperty(TaskPropertyIds.MinSockets, properties);
            task.MaxSockets = GetIntProperty(TaskPropertyIds.MaxSockets, properties);
            task.CommandLine = GetStringProperty(TaskPropertyIds.CommandLine, properties);
            task.RequiredNodes = GetStringProperty(TaskPropertyIds.RequiredNodes, properties);
            task.DependsOn = GetStringProperty(TaskPropertyIds.DependsOn, properties);
            task.IsExclusive = GetBoolProperty(TaskPropertyIds.IsExclusive, properties);
            task.IsRerunnable = GetBoolProperty(TaskPropertyIds.IsRerunnable, properties);
            task.GroupId = GetIntProperty(TaskPropertyIds.GroupId, properties);
            task.StdOutFilePath = GetStringProperty(TaskPropertyIds.StdOutFilePath, properties);
            task.StdInFilePath = GetStringProperty(TaskPropertyIds.StdInFilePath, properties);
            task.StdErrFilePath = GetStringProperty(TaskPropertyIds.StdErrFilePath, properties);
            task.WorkDirectory = GetStringProperty(TaskPropertyIds.WorkDirectory, properties);
            task.StartValue = GetIntProperty(TaskPropertyIds.StartValue, properties);
            task.EndValue = GetIntProperty(TaskPropertyIds.EndValue, properties);
            task.IncrementValue = GetIntProperty(TaskPropertyIds.IncrementValue, properties);
            task.Output = GetStringProperty(TaskPropertyIds.Output, properties);
            task.RequestCancel = GetStringProperty(TaskPropertyIds.RequestCancel, properties);
            task.RequeueCount = GetIntProperty(TaskPropertyIds.RequeueCount, properties);
            task.SubmitTime = GetStringProperty(TaskPropertyIds.SubmitTime, properties);
            task.CreateTime = GetStringProperty(TaskPropertyIds.CreateTime, properties);
            task.StartTime = GetStringProperty(TaskPropertyIds.StartTime, properties);
            task.EndTime = GetStringProperty(TaskPropertyIds.EndTime, properties);
            task.AutoRequeueCount = GetIntProperty(TaskPropertyIds.AutoRequeueCount, properties);
            task.Type = (TaskType)GetEnumProperty(TaskPropertyIds.Type, properties, typeof(TaskType), TaskType.Basic);
            task.AllocatedNodes = GetStringProperty(TaskPropertyIds.AllocatedNodes, properties);

            return task;
        }

        private static void AddProperty<T>(ArrayOfProperty array, PropertyId propertyId, T? property) where T : struct
        {
            if (property.HasValue)
            {
                array.Property.Add(new Property(propertyId, property.ToString()));
            }
        }

        private static void AddProperty(ArrayOfProperty array, PropertyId propertyId, string property)
        {
            if (!string.IsNullOrEmpty(property))
            {
                array.Property.Add(new Property(propertyId, property));
            }
        }

        private static int GetIntProperty(PropertyId propertyId, IEnumerable<Property> properties)
        {
            return GetProperty(propertyId, properties, int.Parse);
        }

        private static DateTime GetDateTimeProperty(PropertyId propertyId, IEnumerable<Property> properties)
        {
            return GetProperty(propertyId, properties, DateTime.Parse);
        }

        private static object GetEnumProperty(PropertyId propertyId, IEnumerable<Property> properties, Type enumType, object defaultValue)
        {
            var value = GetStringProperty(propertyId, properties);
            if (!string.IsNullOrEmpty(value))
            {
                return Enum.Parse(enumType, value);
            }

            return defaultValue;
        }

        private static string GetStringProperty(PropertyId propertyId, IEnumerable<Property> properties)
        {
            var property = properties.FirstOrDefault(x => x.Name.Equals(propertyId.Name));
            if (property != null)
            {
                return property.Value;
            }

            return string.Empty;
        }

        private static bool GetBoolProperty(PropertyId propertyId, IEnumerable<Property> properties)
        {
            return GetProperty(propertyId, properties, bool.Parse);
        }

        private static T GetProperty<T>(PropertyId propertyId, IEnumerable<Property> properties, Func<string, T> parser)
        {
            var property = properties.FirstOrDefault(x => x.Name.Equals(propertyId.Name));
            if (property != null && !string.IsNullOrEmpty(property.Value))
            {
                return parser(property.Value);
            }

            return default(T);
        }
    }
}